fix(process): kill the whole process group on teardown; per-slug tmux env preamble#18
Merged
Merged
Conversation
… slug kill_nohup signaled only the stored PID. Services spawn as 'sh -c <cmd>' in their own process group (process_group(0)) — TERM to the leader killed the wrapper while the actual server survived, kept the port bound, and forced the next up onto an auto-bumped port. Teardown now TERMs the whole group and escalates to KILL after a 2s grace period. spawn_nohup also kills already-spawned services when a later spawn fails instead of orphaning them. The tmux env preamble was one shared .ecluse/env-preamble.sh overwritten by every session's spawn; re-running the setup line in session A's window after session B came up sourced B's ports. The preamble now lives at .ecluse/preambles/<slug>.sh. Fixes #3 https://claude.ai/code/session_017UcuvzMKHVfyBCcq8ipAko
This was referenced Jun 11, 2026
hefgi
added a commit
that referenced
this pull request
Jun 15, 2026
* fix(process): use `./` prefix when sourcing env files in tmux for zsh zsh's POSIX `.` builtin does not search the current directory unless `.` is in `$PATH` — the default macOS shell is zsh, so the bare `. '.env'` form silently failed there with "no such file or directory" even after the cd-first fix from #18. Services in tmux windows ended up without the per-slot env: `ECLUSE_*` vars from the per-slug preamble were fine, but anything from `.env`, `.env.local`, or `.env.ecluse` that wasn't duplicated into the preamble was lost. build_source_preamble now emits `. './.env'` (and the same for `.env.local`/`.env.ecluse`). The `./` prefix is POSIX-correct and works in bash, zsh, and dash. Adds three regression tests covering the correct prefix, the missing-files-skip behavior, and the empty-tree case. Fixes #27 * fix(env): strip outer dotenv quotes when parsing .env files parse_env_file treated everything after `=` as the literal value, which round-tripped `FOO="bar"` as the 5-character value `"bar"` (quotes included) when the value got re-emitted in the per-slug tmux preamble as `export FOO='"bar"'`. Downstream consumers that check against a literal string (e.g. `z.literal("development")`) would reject the quoted value, breaking any framework using conventional dotenv `KEY="value"` style. A matched outer pair of `"..."` or `'...'` is now stripped — the standard dotenv convention where `FOO=bar` and `FOO="bar"` mean the same thing. Unmatched quotes (`FOO="oops`), inner escaped quotes (`MSG="hello \"world\""`), and unquoted values containing literal quote chars or `=` (`URL=postgres://x:5433/db?a=b`) are preserved verbatim, so URLs and query strings round-trip unchanged. Adds seven regression tests covering double, single, unquoted, unmatched, inner-escaped, empty-quoted, and bare-quote-char cases. Fixes #28 * docs: changelog entries for #27 and #28
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3
Process-group kill (orphaned services)
spawn_nohupruns each service assh -c <cmd>in its own process group (process_group(0)) — butkill_nohupsentSIGTERMto the single stored PID. For any compound command theshwrapper died while the actual dev server survived, kept the port bound, and pushed the nextuponto a silently auto-bumped port.kill_nohupnow signals the whole group (kill -TERM -- -<pgid>), polling group liveness and escalating toSIGKILLafter a 2s grace periodspawn_nohupcleans up already-spawned services when a later spawn fails, instead of returningErrand orphaning them (complements the rollback work in "Rollback on failure" is inconsistently enforced — severalbring_upfailure paths orphan containers, worktrees, or delete data volumes #2)Per-slug env preamble (cross-session port leak)
The tmux env preamble was a single shared
.ecluse/env-preamble.sh, overwritten by every session's spawn. Re-running the setup line in session A's tmux window (the manual-restart workflow the file exists for) after session B came up sourced B's ports into A's service — an isolation break in the env-injection mechanism itself..ecluse/preambles/<slug>.shbring_downdelete the session's preamble;flushwipes thepreamblesdir.ecluse-ancestor lookup intoecluse_dir_forTests
kill_nohup_kills_whole_process_group— service spawns a background child; teardown must kill it (fails on the old single-PID kill)spawn_nohup_partial_failure_cleans_up_already_spawnedenv_preamble_file_is_namespaced_per_slug,remove_env_preamble_deletes_only_that_slugcargo fmt --check,cargo clippy -- -D warnings,cargo test(373 + 18) green.https://claude.ai/code/session_017UcuvzMKHVfyBCcq8ipAko
Generated by Claude Code